<?php
/**
 * Note: *
 */
namespace App\Services;

use App\Exceptions\ApiException;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;

class KamiService
{
    protected const API_GET_SECRET = 'http://47.117.129.238:17267/secret';
    protected const API_QUERY_BALANCE = 'http://47.117.129.238:9001/v1.0/QueryBalance.ashx';

    public const PRODUCT_TYPE_HF = 1; // 话费
    public const PRODUCT_TYPE_YK = 2; // 油卡
    public const PRODUCT_TYPE_JD = 3; // 京东E卡

    public const CARD_TYPE_YD = 0; // 移动
    public const CARD_TYPE_LT = 1; // 联通
    public const CARD_TYPE_DX = 2; // 电信
    public const CARD_TYPE_GH = 3; // 固话
    public const CARD_TYPE_ZSH = 4; // 中石化
    public const CARD_TYPE_ZSY = 5; // 中石油
    public const CARD_TYPE_JD = 6; // 京东E卡

    protected static $configs = [];

    protected function getConfig($key = null)
    {
        if (!self::$configs) self::$configs = config('services.kami');

        return $key ? (self::$configs[$key] ?? null) : self::$configs;
    }

    /**
     * 发送get请求
     * @param $url
     * @param $data
     * @return Response
     * @throws \Exception
     */
    protected function requestGet($url, $data): Response
    {
        // 发生错误时 100ms 后重试 1 次, 每次超时3s (设置timeout之后, 如果超时会直接抛出异常, 不到 $response->throw), 这里放入try
        try {
            info(__METHOD__, [$url, $data]);
            $response = Http::retry(2, 100)->timeout(3)->asForm()->get($url, $data);
            $response->throw();
            info(__METHOD__, [$response]);
        } catch (\Exception $e) {
            report($e);
            throw new \Exception("卡密服务正在维护中，请联系客服");
        }
        return $response;
    }

    /**
     * 生成签名
     * @param array $params
     * @return string
     */
    protected function makeSign(array $params): string
    {
        return md5($params['user_id'].$params['product_type'].$params['card_type'].$params['amount'].$this->getConfig('key'));
    }

    /**
     * 获取密钥
     * @param string $orderid
     * @param int $prodcutType
     * @param int $cardType
     * @param int $amount
     * @return array [$torderid, $cardno, $cardpass]
     * @throws \Exception
     */
    public function getSecret(string $orderid, int $prodcutType, int $cardType, int $amount): array
    {
        $params['user_order_id'] = $orderid;
        $params['user_id'] = $this->getConfig('user_id');
        $params['product_type'] = $prodcutType;
        $params['card_type'] = $cardType;
        $params['amount'] = $amount;
        $params['sign'] = $this->makeSign($params);
        $response = $this->requestGet(self::API_GET_SECRET, $params);
        if ($response['code'] != '2000') {
            if ($response['code'] == '10027') {
                throw new ApiException('兑换失败, 库存不足, 请明日再试');
            }
            throw new \Exception('兑换失败: '.$response['message']);
        }
        $data = $response['data'];
        return [$data['system_order_id'], $data['account'], $data['secret']];
    }

    /**
     * 获取权益交换卡余额
     * @return int
     * @throws \Exception
     */
    public function getBalance(): int
    {
        $params['ShopId'] = $this->getConfig('shop_id');
        $params['UserId'] = $this->getConfig('user_id');
        $params['Timestamp'] = time();
        $params['Sign'] = md5($params['ShopId'] . $params['UserId'] . $params['Timestamp'] . $this->getConfig('key'));
        $response = $this->requestGet(self::API_QUERY_BALANCE, $params);
        if ($response['Code'] != 10000) {
            throw new \Exception('权益交换卡余额查询失败: '.$response['Message']);
        }
        return $response['Balance'];
    }

    /**
     * 加密
     * @param string $data
     * @param string $key
     * @return string
     */
    public function encrypt(string $data, string $key = ''): string
    {
        if (empty($key)) $key = $this->getConfig('key');
        $iv = substr($key, 0, 16);
        $ciphertext = openssl_encrypt($data, "aes-256-cbc", $key, 1, $iv);
        return base64_encode($ciphertext);
    }

    /**
     * 解密
     * @param string $data
     * @param string $key
     * @return false|string
     */
    public function decrypt(string $data, string $key = '')
    {
        if (empty($key)) $key = $this->getConfig('key');
        $iv = substr($key, 0, 16);
        $ciphertext = base64_decode($data);
        return openssl_decrypt($ciphertext, "aes-256-cbc", $key, 1, $iv);
    }
}
